﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using JaernCloud.Language.Compiler.Ast;

namespace JaernCloud.ClassificationGenerator {
    class Program {
        static void Main(string[] args) {
            if (args.Length != 1)
                Environment.Exit(1); // Incorrect number of arguments

            targetLocation = args[0];
            if (!Directory.Exists(targetLocation))
                Environment.Exit(2); // Could not find output directory

            System.IO.FileInfo fileInfo = new System.IO.FileInfo(@"..\..\..\Language\Compiler\Ast\AstNodeKind.cs");
            DateTime nodeKindLastModified = fileInfo.LastWriteTime;
            fileInfo = new System.IO.FileInfo(@"..\..\..\VisualStudio\Classification\ClassifictionType.cs");
            DateTime classificationLastModified = fileInfo.LastWriteTime;
            fileInfo = new System.IO.FileInfo(@"..\..\..\VisualStudio\Classification\AstNodeKindColorization.cs");
            DateTime colorizationLastModified = fileInfo.LastWriteTime;

            if (nodeKindLastModified < classificationLastModified && nodeKindLastModified < colorizationLastModified)
                Environment.Exit(0);

            StringBuilder classificationTypesBuilder = new StringBuilder();
            PrepareFile(classificationTypesBuilder);

            classificationTypesBuilder.AppendLine("using System.ComponentModel.Composition;")
                                      .AppendLine("using Microsoft.VisualStudio.Text.Classification;")
                                      .AppendLine("using Microsoft.VisualStudio.Utilities;")
                                      .AppendLine()
                                      .AppendLine("namespace JaernCloud.VisualStudio.Classification {")
                                      .AppendLine()
                                      .AppendLine("\tinternal static class ClassificationTypes {");

            foreach (AstNodeKind astNodeKind in Enum.GetValues(typeof(AstNodeKind))) {
                GenerateClassificationType(astNodeKind, classificationTypesBuilder);
                GenerateClassificationFormat(astNodeKind, targetLocation);
            }

            // TODO: Create types and formats for AstOperator, AstConstant, AstConstantValueKind

            classificationTypesBuilder.AppendLine("\t}")
                                      .AppendLine("}");

            File.WriteAllText(Path.Combine(targetLocation, "ClassificationTypes.cs"), classificationTypesBuilder.ToString());
        }

        /// <summary>
        ///     <example>
        ///         [Export(typeof(ClassificationTypeDefinition))]
        ///         [Name("JaernCloud_None")]
        ///         internal static ClassificationTypeDefinition jcNone = null;
        ///     </example>
        /// </summary>
        static void GenerateClassificationType(AstNodeKind astNodeKind, StringBuilder classificationTypesBuilder) {
            classificationTypesBuilder.AppendLine("\t\t[Export(typeof(ClassificationTypeDefinition))]")
                                      .AppendLine(String.Format("\t\t[Name(\"JaernCloud_{0}\")]", astNodeKind.ToString()))
                                      .AppendLine(String.Format("\t\tinternal static ClassificationTypeDefinition jc{0} = null;", astNodeKind.ToString()))
                                      .AppendLine();
        }

        /// <summary>
        ///     <example>
        ///         [Export(typeof(EditorFormatDefinition))]
        ///         [ClassificationType(ClassificationTypeNames = "JaernCloud_None")]
        ///         [Name("JaernCloud_None")]
        ///         [UserVisible(false)]
        ///         [Order(Before = Priority.Default)]
        ///         internal sealed class JaernCloudNone : ClassificationFormatDefinition {
        ///             public JaernCloudNone() {
        ///                 this.DisplayName = "None";
        ///                 this.ForegroundColor = Colors.Black;
        ///             }
        ///         }
        ///     </example>
        /// </summary>
        static void GenerateClassificationFormat(AstNodeKind astNodeKind, string path) {
            StringBuilder classificationFormat = new StringBuilder();
            PrepareFile(classificationFormat);

            classificationFormat.AppendLine("using System.ComponentModel.Composition;")
                                .AppendLine("using System.Windows.Media;")
                                .AppendLine("using Microsoft.VisualStudio.Text.Classification;")
                                .AppendLine("using Microsoft.VisualStudio.Utilities;")
                                .AppendLine("using JaernCloud.Language.Compiler.Ast;")
                                .AppendLine()
                                .AppendLine("namespace JaernCloud.VisualStudio.Classification {");

            classificationFormat.AppendLine("\t[Export(typeof(EditorFormatDefinition))]");
            classificationFormat.AppendLine(String.Format("\t[ClassificationType(ClassificationTypeNames = \"JaernCloud_{0}\")]", astNodeKind.ToString()));
            classificationFormat.AppendLine(String.Format("\t[Name(\"JaernCloud_{0}\")]", astNodeKind.ToString()));
            classificationFormat.AppendLine("\t[UserVisible(false)]");
            classificationFormat.AppendLine("\t[Order(Before = Priority.Default)]");
            classificationFormat.AppendLine(String.Format("\tinternal sealed class JaernCloud{0} : ClassificationFormatDefinition {{", astNodeKind.ToString()));
            classificationFormat.AppendLine(String.Format("\t\tpublic JaernCloud{0}() {{", astNodeKind.ToString()));
            classificationFormat.AppendLine(String.Format("\t\t\tthis.DisplayName = \"{0}\";", astNodeKind.ToString()));
            classificationFormat.AppendLine(String.Format("\t\t\tthis.ForegroundColor = AstNodeKindColorization.Colorization[AstNodeKind.{0}];", astNodeKind));
            classificationFormat.AppendLine("\t\t}");
            classificationFormat.AppendLine("\t}");

            classificationFormat.AppendLine("}");

            File.WriteAllText(Path.Combine(Path.Combine(targetLocation, "Format"), String.Format("JaernCloud{0}.cs", astNodeKind.ToString())), classificationFormat.ToString());
        }

        static void PrepareFile(StringBuilder file) {
            file.AppendLine("// ")
                .AppendLine("//    Copyright 2010 The JaernCloud Project")
                .AppendLine("// ")
                .AppendLine("//    Licensed under the Apache License, Version 2.0 (the \"License\");")
                .AppendLine("//    you may not use this file except in compliance with the License.")
                .AppendLine("//    You may obtain a copy of the License at")
                .AppendLine("// ")
                .AppendLine("//        http://www.apache.org/licenses/LICENSE-2.0")
                .AppendLine("// ")
                .AppendLine("//    Unless required by applicable law or agreed to in writing, software")
                .AppendLine("//    distributed under the License is distributed on an \"AS IS\" BASIS,")
                .AppendLine("//    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.")
                .AppendLine("//    See the License for the specific language governing permissions and")
                .AppendLine("//    limitations under the License.")
                .AppendLine("// ")
                .AppendLine();
        }

        private static string targetLocation;
    }
}
